#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <error.h>

#include "tcpsrv.h"

struct queue_table * queue_head[3];
struct event_table * event_head;

/**
* I initialized 3 queue link, one for hourly loop, and the second for minutly, and the third for secondly
* I will create a hash table soon
*/

// Queue table initialize
int queue_table_init()
{

	queue_head[0] = malloc(sizeof(struct queue_table));
	queue_head[1] = malloc(sizeof(struct queue_table));
	queue_head[2] = malloc(sizeof(struct queue_table));
	
	queue_head[0] -> next = NULL;
	queue_head[1] -> next = NULL;
	queue_head[2] -> next = NULL;
	
	return 0;
}

// Add a queue table
struct queue_table * queue_table_add(int queue_interval_id)
{
	struct queue_table * next_table, * tail;
	if (queue_interval_id <= 2 && queue_interval_id >= 0)
	{
		next_table = malloc(sizeof(struct queue_table));
		tail = queue_head[queue_interval_id];
		while (tail -> next)
		{
			tail = tail -> next;
		}
		
		tail -> next = next_table;
		next_table -> next = NULL;
	}
	
	return next_table;
}

// Add an event item into queue table
int queue_item_add(int item_id, time_t end_time, int queue_interval_id)
{
	struct queue_table * curr = queue_head[queue_interval_id];
	int j = 0, i = 0, id = -1;
	
	if (queue_interval_id <= 2 && queue_interval_id >= 0)
	{
		// Find a blank slab
		while (curr)
		{
			for (i = 0; i < QUEUE_TABLE_SIZE; i ++)
			{
				if (0 == curr -> table[i] . item_id)
				{
					curr -> table[i] . item_id = item_id;
					curr -> table[i] . end_time = end_time;
					id = j * QUEUE_TABLE_SIZE + i;
					break;
				}
			}
			
			if (id >= 0)
			{
				break;
			}
			j ++;
			curr = curr -> next;
		}
		
		if (id < 0)
		{
			// Add a new queue table node
			curr = queue_table_add(queue_interval_id);
			
			curr -> table[0] . item_id = item_id;
			curr -> table[0] . end_time = end_time;
			
			id = j * QUEUE_TABLE_SIZE;
		}
	}
	
	return id;
}

// Event table initialize
int event_table_init()
{
	event_head = malloc(sizeof(struct event_table));
	event_head -> next = NULL;
	
	return 0;
}

// Add an event table
struct event_table * event_table_add()
{
	struct event_table * next_table, * tail;
	int i;
	
	next_table = malloc(sizeof(struct event_table));
	for (i = 0; i < EVENT_TABLE_SIZE; i ++)
	{
		next_table -> table[i] . start_time = 0;
	}
	
	tail = event_head;
	while (tail -> next)
	{
		tail = tail -> next;
	}
	
	tail -> next = next_table;
	next_table -> next = NULL;
	
	return next_table;
}

// Add an event item into event table
int event_item_add(int loop, int interval, unsigned char * cmd)
{
	time_t start_time = time((time_t *) NULL);
	time_t end_time = start_time + (time_t) interval;
	
	int j = 0, i = 0, id = -1, queue_interval_id;
	
	if (interval > 3600)
	{
		queue_interval_id = 0;
	}
	
	else if (interval > 60)
	{
		queue_interval_id = 1;
	}
	
	else
	{
		queue_interval_id = 2;
	}
	
	// Found a blank table item
	struct event_table * curr = event_head;
	while (curr)
	{
		for (i = 0; i < EVENT_TABLE_SIZE; i++)
		{
			if (!curr -> table[i] . start_time)
			{
				curr -> table[i] . start_time = start_time;
				curr -> table[i] . loop = loop;
				curr -> table[i] . interval = interval;
				strncpy(curr -> table[i] . cmd, cmd, (strlen(cmd) > CMD_LENGTH ? CMD_LENGTH : strlen(cmd)));
				
				id = j * EVENT_TABLE_SIZE + i;
				break;
			} 
		}
		
		if (id >= 0)
		{
			break;
		}
		j ++;
		curr = curr -> next;
	}
	
	// All full...
	if (id < 0)
	{
		// Add a new event table node
		curr = event_table_add();
		
		curr -> table[0] . start_time = start_time;
		curr -> table[0] . loop = loop;
		curr -> table[0] . interval = interval;
		strncpy(curr -> table[0] . cmd, cmd, (strlen(cmd) > CMD_LENGTH ? CMD_LENGTH : strlen(cmd)));
		
		id = j * EVENT_TABLE_SIZE;
	}
	
	id += EVENT_ID_ALIGN;
	queue_item_add(id, end_time, queue_interval_id);
	
	return id;
}

// Find event from table
struct event_item * event_item_find(int item_id)
{
	int j = 0, i = 0, k = 0;
	
	item_id -= EVENT_ID_ALIGN;
	if (item_id < 0)
	{
		item_id = 0;
	}
	
	j = item_id / EVENT_TABLE_SIZE;
	i = item_id % EVENT_TABLE_SIZE;
	
	struct event_table * curr = event_head;
	
	for (k = 0; k < j; k ++)
	{
		if (curr -> next)
		{
			curr = curr -> next;
		}
	}
	
	return &curr -> table[i];
}

// Mark event blank
int event_item_delete(int item_id)
{
	int j = 0, i = 0, k = 0;
	
	item_id -= EVENT_ID_ALIGN;
	j = item_id / EVENT_TABLE_SIZE;
	i = item_id % EVENT_TABLE_SIZE;
	
	struct event_table * curr = event_head;
	
	for (k = 0; k < j; k ++)
	{
		if (curr -> next)
		{
			curr = curr -> next;
		}
		
		else return -1;
	}
	
	curr -> table[i] . start_time = 0;
	
	return 0;
}
